<!DOCTYPE html>
<html lang="en"><head>
    <title>CZH-DEV BLOG</title>
    <meta content="text/html;charset=utf-8" http-equiv="Content-Type">
    <meta content="utf-8" http-equiv="encoding">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta name="format-detection" content="telephone=no" />
    <meta name="theme-color" content="#000084" />
    <link rel="icon" href="https://czh-dev.gitee.io/czh-blog.gitee.io//favicon.ico">
    <link rel="canonical" href="https://czh-dev.gitee.io/czh-blog.gitee.io/">
    
    
</head>
<body>
<nav class="navbar navbar-inverse navbar-fixed-top">
    <div class="navbar-inner">
        <div class="container">
            <button type="button" class="btn btn-navbar" data-toggle="collapse" data-target=".nav-collapse"></button>
            <a class="brand" href="https://czh-dev.gitee.io/czh-blog.gitee.io/">CZH-DEV BLOG</a>
            <div class="nav-collapse collapse">
                <ul class="nav">
                    
                    
                        
                            <li>
                                <a href="/czh-blog.gitee.io/about/">
                                    
                                    <span>About</span>
                                </a>
                            </li>
                        
                    
                        
                            <li>
                                <a href="/czh-blog.gitee.io/post/">
                                    
                                    <span>All posts</span>
                                </a>
                            </li>
                        
                    
                        
                            <li>
                                <a href="/czh-blog.gitee.io/ebook/">
                                    
                                    <span>Resource</span>
                                </a>
                            </li>
                        
                    
                </ul>
            </div>
        </div>
    </div>
</nav><div id="content" class="container">
<div style="display: flex;">
  <div class="row-fluid navmargin">
    <div class="page-header">
      <h1>Spring Cloud Alibaba（Ⅶ） - Sat, Feb 11, 2023</h1>
    </div>
    <p class="lead"></p>
    <h1 id="第七章-服务网关gateway">第七章 服务网关Gateway</h1>
<p>大家都都知道在微服务架构中，一个系统会被拆分为很多个微服务。那么作为客户端要如何去调用这么多的微服务呢？如果没有网关的存在，我们只能在客户端记录每个微服务的地址，然后分别去调用。</p>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111459936.png" alt="image-20201030144013742"></strong></p>
<p>这样的架构，会存在着诸多的问题：</p>
<ul>
<li>
<p>客户端多次请求不同的微服务，增加客户端代码或配置编写的复杂性</p>
</li>
<li>
<p>认证复杂，每个服务都需要独立认证。</p>
</li>
<li>
<p>微服务做集群的情况下，客户端并没有负责均衡的功能</p>
</li>
</ul>
<p>上面的这些问题可以借助<strong>API网关</strong>来解决。</p>
<p>所谓的API网关，就是指系统的<strong>统一入口</strong>，它封装了应用程序的内部结构，为客户端提供统一服</p>
<p>务，一些与业务本身功能无关的公共逻辑可以在这里实现，诸如认证、鉴权、监控、路由转发等等。</p>
<p>添加上API网关之后，系统的架构图变成了如下所示：</p>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111459125.png" alt="image-20201030144534269"></strong></p>
<p>网关是如何知道微服务的地址?网关如何进行负载均衡呢？</p>
<p>网关需要将自己的信息注册到注册中心上并且拉取其他微服务的信息，然后再调用的时候基于Ribbon实现负载均衡</p>
<h2 id="71-常见网关介绍">7.1 常见网关介绍</h2>
<ul>
<li><strong>Ngnix+lua</strong></li>
</ul>
<p>使用nginx的反向代理和负载均衡可实现对api服务器的负载均衡及高可用,lua是一种脚本语言,可以来编写一些简单的逻辑, nginx支持lua脚本</p>
<ul>
<li><strong>Kong</strong></li>
</ul>
<p>基于Nginx+Lua开发，性能高，稳定，有多个可用的插件(限流、鉴权等等)可以开箱即用。 问题：只支持Http协议；二次开发，自由扩展困难；提供管理API，缺乏更易用的管控、配置方式。</p>
<ul>
<li><strong>Zuul</strong></li>
</ul>
<p>Netflflix开源的网关，功能丰富，使用JAVA开发，易于二次开发 问题：缺乏管控，无法动态配置；依赖组件较多；处理Http请求依赖的是Web容器，性能不如Nginx,Spring Cloud Gateway</p>
<p>Spring公司为了替换Zuul而开发的网关服务，将在下面具体介绍。</p>
<p>注意：SpringCloud alibaba技术栈中并没有提供自己的网关，我们可以采用Spring Cloud Gateway</p>
<p>来做网关</p>
<h2 id="72-gateway简介">7.2 Gateway简介</h2>
<p>​	Spring Cloud Gateway是Spring公司基于Spring 5.0，Spring Boot 2.0 和 Project Reactor 等技术开发的网关，它旨在为微服务架构提供一种简单有效的统一的 API 路由管理方式。它的目标是替代</p>
<p>Netflflix Zuul，其不仅提供统一的路由方式，并且基于 Filter 链的方式提供了网关基本的功能，例如：安</p>
<p>全，监控和限流。</p>
<p><strong>优点：</strong></p>
<ul>
<li>
<p>性能强劲：是第一代网关Zuul的1.6倍</p>
</li>
<li>
<p>功能强大：内置了很多实用的功能，例如转发、监控、限流等</p>
</li>
<li>
<p>设计优雅，容易扩展</p>
</li>
</ul>
<p><strong>缺点：</strong></p>
<ul>
<li>
<p>其实现依赖Netty与WebFlux，不是传统的Servlet编程模型，学习成本高</p>
</li>
<li>
<p>不能将其部署在Tomcat、Jetty等Servlet容器里，只能打成jar包执行</p>
</li>
<li>
<p>需要Spring Boot 2.0及以上的版本，才支持</p>
</li>
</ul>
<h2 id="73-gateway快速入门">7.3 Gateway快速入门</h2>
<ol>
<li>
<p>创建一个 api-gateway 的模块,导入相关依赖</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-xml" data-lang="xml"><span style="display:flex;"><span><span style="color:#75715e">&lt;?xml version=&#34;1.0&#34; encoding=&#34;UTF-8&#34;?&gt;</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">&lt;project</span> <span style="color:#a6e22e">xmlns=</span><span style="color:#e6db74">&#34;http://maven.apache.org/POM/4.0.0&#34;</span>
</span></span><span style="display:flex;"><span>         <span style="color:#a6e22e">xmlns:xsi=</span><span style="color:#e6db74">&#34;http://www.w3.org/2001/XMLSchema-instance&#34;</span>
</span></span><span style="display:flex;"><span>         <span style="color:#a6e22e">xsi:schemaLocation=</span><span style="color:#e6db74">&#34;http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd&#34;</span><span style="color:#f92672">&gt;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">&lt;parent&gt;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">&lt;artifactId&gt;</span>shop-parent<span style="color:#f92672">&lt;/artifactId&gt;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">&lt;groupId&gt;</span>cn.czh0123<span style="color:#f92672">&lt;/groupId&gt;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">&lt;version&gt;</span>1.0.0<span style="color:#f92672">&lt;/version&gt;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">&lt;/parent&gt;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">&lt;modelVersion&gt;</span>4.0.0<span style="color:#f92672">&lt;/modelVersion&gt;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">&lt;artifactId&gt;</span>api-gateway<span style="color:#f92672">&lt;/artifactId&gt;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">&lt;dependencies&gt;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#75715e">&lt;!--gateway网关--&gt;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">&lt;dependency&gt;</span>
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">&lt;groupId&gt;</span>org.springframework.cloud<span style="color:#f92672">&lt;/groupId&gt;</span>
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">&lt;artifactId&gt;</span>spring-cloud-starter-gateway<span style="color:#f92672">&lt;/artifactId&gt;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">&lt;/dependency&gt;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#75715e">&lt;!--nacos客户端--&gt;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">&lt;dependency&gt;</span>
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">&lt;groupId&gt;</span>com.alibaba.cloud<span style="color:#f92672">&lt;/groupId&gt;</span>
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">&lt;artifactId&gt;</span>spring-cloud-starter-alibaba-nacos-discovery<span style="color:#f92672">&lt;/artifactId&gt;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">&lt;/dependency&gt;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">&lt;dependency&gt;</span>
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">&lt;groupId&gt;</span>org.projectlombok<span style="color:#f92672">&lt;/groupId&gt;</span>
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">&lt;artifactId&gt;</span>lombok<span style="color:#f92672">&lt;/artifactId&gt;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">&lt;/dependency&gt;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">&lt;/dependencies&gt;</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">&lt;/project&gt;</span>
</span></span></code></pre></div></li>
<li>
<p>编写启动类</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#a6e22e">@SpringBootApplication</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">@EnableDiscoveryClient</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">ApiGatewayServer</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">static</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">main</span><span style="color:#f92672">(</span>String<span style="color:#f92672">[]</span> args<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        SpringApplication<span style="color:#f92672">.</span><span style="color:#a6e22e">run</span><span style="color:#f92672">(</span>ApiGatewayServer<span style="color:#f92672">.</span><span style="color:#a6e22e">class</span><span style="color:#f92672">,</span>args<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div></li>
<li>
<p>编写配置文件</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#f92672">server</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">port</span>: <span style="color:#ae81ff">9000</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">spring</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">application</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">name</span>: <span style="color:#ae81ff">api-gateway</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">cloud</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">nacos</span>:
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">discovery</span>:
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">server-addr</span>: <span style="color:#ae81ff">localhost:8848</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">gateway</span>:
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">discovery</span>:
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">locator</span>:
</span></span><span style="display:flex;"><span>          <span style="color:#f92672">enabled</span>: <span style="color:#66d9ef">true</span> <span style="color:#75715e"># 让gateway可以发现nacos中的微服务</span>
</span></span></code></pre></div></li>
<li>
<p>启动测试</p>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111500669.png" alt="image-20201030152917728"></strong></p>
</li>
</ol>
<h2 id="74-自定义路由规则">7.4 自定义路由规则</h2>
<ol>
<li>
<p>在application.yml中添加新的路由规则</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#f92672">spring</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">cloud</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">gateway</span>:
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">routes</span>:
</span></span><span style="display:flex;"><span>        - <span style="color:#f92672">id</span>: <span style="color:#ae81ff">product_route</span>
</span></span><span style="display:flex;"><span>          <span style="color:#f92672">uri</span>: <span style="color:#ae81ff">lb://product-service </span>
</span></span><span style="display:flex;"><span>          <span style="color:#f92672">predicates</span>:
</span></span><span style="display:flex;"><span>            - <span style="color:#ae81ff">Path=/product-serv/**</span>
</span></span><span style="display:flex;"><span>          <span style="color:#f92672">filters</span>:
</span></span><span style="display:flex;"><span>            - <span style="color:#ae81ff">StripPrefix=1</span>
</span></span><span style="display:flex;"><span>        - <span style="color:#f92672">id</span>: <span style="color:#ae81ff">order_route</span>
</span></span><span style="display:flex;"><span>          <span style="color:#f92672">uri</span>: <span style="color:#ae81ff">lb://order-service </span>
</span></span><span style="display:flex;"><span>          <span style="color:#f92672">predicates</span>:
</span></span><span style="display:flex;"><span>            - <span style="color:#ae81ff">Path=/order-serv/**</span>
</span></span><span style="display:flex;"><span>          <span style="color:#f92672">filters</span>:
</span></span><span style="display:flex;"><span>            - <span style="color:#ae81ff">StripPrefix=1</span>
</span></span></code></pre></div></li>
<li>
<p>启动测试</p>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111500971.png" alt="image-20201030154027833"></strong></p>
</li>
</ol>
<h2 id="75-gateway概念">7.5 Gateway概念</h2>
<p>路由(Route) 是 gateway 中最基本的组件之一，表示一个具体的路由信息载体。主要定义了下面的几个</p>
<p>信息:</p>
<ul>
<li>
<p><strong>id</strong>，路由标识符，区别于其他 Route。</p>
</li>
<li>
<p><strong>uri</strong>，路由指向的目的地 uri，即客户端请求最终被转发到的微服务。</p>
</li>
<li>
<p><strong>order</strong>，用于多个 Route 之间的排序，数值越小排序越靠前，匹配优先级越高。</p>
</li>
<li>
<p><strong>predicate</strong>，断言的作用是进行条件判断，只有断言都返回真，才会真正的执行路由。</p>
</li>
<li>
<p><strong>filter</strong>，过滤器用于修改请求和响应信息。</p>
</li>
</ul>
<p>执行流程图:</p>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111500962.png" alt="image-20201030161652819"></strong></p>
<h2 id="76-过滤器filter">7.6 过滤器Filter</h2>
<p>过滤器就是在请求的传递过程中,对请求和响应做一些手脚.</p>
<p>在Gateway中, Filter的生命周期只有两个：“pre” 和 “post”。</p>
<ul>
<li>
<p>PRE： 这种过滤器在请求到调用的业务服务之前调用。我们可利用这种过滤器实现身份验证、在集群中选择请求的微服务、记录调试信息等。</p>
</li>
<li>
<p>POST：这种过滤器在访问到微服务以后执行。这种过滤器可用来为响应添加标准的HTTPHeader、收集统计信息和指标、将响应从微服务发送给客户端等。</p>
</li>
</ul>
<p>在Gateway中，Filter的作用范围两种:</p>
<ul>
<li>
<p>GatewayFilter：应用到单个路由或者一个分组的路由上。</p>
</li>
<li>
<p>GlobalFilter：应用到所有的路由上</p>
</li>
</ul>
<h3 id="761-局部路由过滤器">7.6.1 局部路由过滤器</h3>
<p>局部过滤器是针对单个路由的过滤器,在SpringCloud Gateway中内置了很多不同类型的网关路由过滤器,有兴趣同学可以自行了解，这里太多了，我们就不一一讲解，我们主要来讲一下自定义路由过滤器。</p>
<p>需求: 统计订单服务调用耗时.</p>
<ol>
<li>
<p>编写Filter类，注意名称是有固定格式xxxGatewayFilterFactory</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#f92672">package</span> cn.czh0123.filters<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">@Component</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">TimeGatewayFilterFactory</span> <span style="color:#66d9ef">extends</span> AbstractGatewayFilterFactory<span style="color:#f92672">&lt;</span>TimeGatewayFilterFactory<span style="color:#f92672">.</span><span style="color:#a6e22e">Config</span><span style="color:#f92672">&gt;{</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">private</span> <span style="color:#66d9ef">static</span> <span style="color:#66d9ef">final</span> String BEGIN_TIME <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;beginTime&#34;</span><span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">//构造函数
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>    <span style="color:#66d9ef">public</span> <span style="color:#a6e22e">TimeGatewayFilterFactory</span><span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">super</span><span style="color:#f92672">(</span>TimeGatewayFilterFactory<span style="color:#f92672">.</span><span style="color:#a6e22e">Config</span><span style="color:#f92672">.</span><span style="color:#a6e22e">class</span><span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">//读取配置文件中的参数 赋值到 配置类中
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>    <span style="color:#a6e22e">@Override</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> List<span style="color:#f92672">&lt;</span>String<span style="color:#f92672">&gt;</span> <span style="color:#a6e22e">shortcutFieldOrder</span><span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> Arrays<span style="color:#f92672">.</span><span style="color:#a6e22e">asList</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;show&#34;</span><span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@Override</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> GatewayFilter <span style="color:#a6e22e">apply</span><span style="color:#f92672">(</span>Config config<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> <span style="color:#66d9ef">new</span> GatewayFilter<span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>            <span style="color:#a6e22e">@Override</span>
</span></span><span style="display:flex;"><span>            <span style="color:#66d9ef">public</span> Mono<span style="color:#f92672">&lt;</span>Void<span style="color:#f92672">&gt;</span> <span style="color:#a6e22e">filter</span><span style="color:#f92672">(</span>ServerWebExchange exchange<span style="color:#f92672">,</span> GatewayFilterChain chain<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>                <span style="color:#66d9ef">if</span><span style="color:#f92672">(!</span>config<span style="color:#f92672">.</span><span style="color:#a6e22e">show</span><span style="color:#f92672">){</span>
</span></span><span style="display:flex;"><span>                    <span style="color:#66d9ef">return</span> chain<span style="color:#f92672">.</span><span style="color:#a6e22e">filter</span><span style="color:#f92672">(</span>exchange<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>                <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>                exchange<span style="color:#f92672">.</span><span style="color:#a6e22e">getAttributes</span><span style="color:#f92672">().</span><span style="color:#a6e22e">put</span><span style="color:#f92672">(</span>BEGIN_TIME<span style="color:#f92672">,</span> System<span style="color:#f92672">.</span><span style="color:#a6e22e">currentTimeMillis</span><span style="color:#f92672">());</span>
</span></span><span style="display:flex;"><span>                <span style="color:#75715e">/**
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">                 *  pre的逻辑
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">                 * chain.filter().then(Mono.fromRunable(()-&gt;{
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">                 *     post的逻辑
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">                 * }))
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">                 */</span>
</span></span><span style="display:flex;"><span>                <span style="color:#66d9ef">return</span> chain<span style="color:#f92672">.</span><span style="color:#a6e22e">filter</span><span style="color:#f92672">(</span>exchange<span style="color:#f92672">).</span><span style="color:#a6e22e">then</span><span style="color:#f92672">(</span>Mono<span style="color:#f92672">.</span><span style="color:#a6e22e">fromRunnable</span><span style="color:#f92672">(()-&gt;{</span>
</span></span><span style="display:flex;"><span>                    Long startTime <span style="color:#f92672">=</span> exchange<span style="color:#f92672">.</span><span style="color:#a6e22e">getAttribute</span><span style="color:#f92672">(</span>BEGIN_TIME<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>                    <span style="color:#66d9ef">if</span> <span style="color:#f92672">(</span>startTime <span style="color:#f92672">!=</span> <span style="color:#66d9ef">null</span><span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>                        System<span style="color:#f92672">.</span><span style="color:#a6e22e">out</span><span style="color:#f92672">.</span><span style="color:#a6e22e">println</span><span style="color:#f92672">(</span>exchange<span style="color:#f92672">.</span><span style="color:#a6e22e">getRequest</span><span style="color:#f92672">().</span><span style="color:#a6e22e">getURI</span><span style="color:#f92672">()</span> <span style="color:#f92672">+</span> <span style="color:#e6db74">&#34;请求耗时: &#34;</span> <span style="color:#f92672">+</span> <span style="color:#f92672">(</span>System<span style="color:#f92672">.</span><span style="color:#a6e22e">currentTimeMillis</span><span style="color:#f92672">()</span> <span style="color:#f92672">-</span> startTime<span style="color:#f92672">)</span> <span style="color:#f92672">+</span> <span style="color:#e6db74">&#34;ms&#34;</span><span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>                    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>                <span style="color:#f92672">}));</span>
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">};</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@Setter@Getter</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">static</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">Config</span><span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">private</span> <span style="color:#66d9ef">boolean</span> show<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div></li>
<li>
<p>在指定的路由中添加路由规则</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#f92672">server</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">port</span>: <span style="color:#ae81ff">9000</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">spring</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">application</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">name</span>: <span style="color:#ae81ff">api-gateway</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">cloud</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">nacos</span>:
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">discovery</span>:
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">server-addr</span>: <span style="color:#ae81ff">localhost:8848</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">gateway</span>:
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">discovery</span>:
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">locator</span>:
</span></span><span style="display:flex;"><span>          <span style="color:#f92672">enabled</span>: <span style="color:#66d9ef">true</span> 
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">routes</span>:
</span></span><span style="display:flex;"><span>        - <span style="color:#f92672">id</span>: <span style="color:#ae81ff">product_route</span>
</span></span><span style="display:flex;"><span>          <span style="color:#f92672">uri</span>: <span style="color:#ae81ff">lb://product-service </span>
</span></span><span style="display:flex;"><span>          <span style="color:#f92672">predicates</span>:
</span></span><span style="display:flex;"><span>            - <span style="color:#ae81ff">Path=/product-serv/**</span>
</span></span><span style="display:flex;"><span>          <span style="color:#f92672">filters</span>:
</span></span><span style="display:flex;"><span>            - <span style="color:#ae81ff">StripPrefix=1</span>
</span></span><span style="display:flex;"><span>        - <span style="color:#f92672">id</span>: <span style="color:#ae81ff">order_route</span>
</span></span><span style="display:flex;"><span>          <span style="color:#f92672">uri</span>: <span style="color:#ae81ff">lb://order-service </span>
</span></span><span style="display:flex;"><span>          <span style="color:#f92672">predicates</span>:
</span></span><span style="display:flex;"><span>            - <span style="color:#ae81ff">Path=/order-serv/**</span>
</span></span><span style="display:flex;"><span>          <span style="color:#f92672">filters</span>:
</span></span><span style="display:flex;"><span>            - <span style="color:#ae81ff">StripPrefix=1</span>
</span></span><span style="display:flex;"><span>            - <span style="color:#ae81ff">Time=true</span>
</span></span></code></pre></div></li>
<li>
<p>访问商品服务的时候是没有打印日志的，访问订单服务的时候打印入职如下:</p>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111500447.png" alt="image-20201030171007704"></strong></p>
</li>
</ol>
<h3 id="762-全局路由过滤器">7.6.2 全局路由过滤器</h3>
<p>全局过滤器作用于所有路由, 无需配置。通过全局过滤器可以实现对权限的统一校验，安全性验证等功</p>
<p>能。</p>
<p>SpringCloud Gateway内部也是通过一系列的内置全局过滤器对整个路由转发进行处理如下：</p>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111500984.jpg" alt=""></strong></p>
<p>需求: 实现统一鉴权的功能,我们需要在网关判断请求中是否包含token且，如果没有则不转发路由，有则执行正常逻辑。</p>
<ol>
<li>
<p>编写全局过滤类</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#f92672">package</span> cn.czh0123.filters<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">@Component</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">AuthGlobalFilter</span> <span style="color:#66d9ef">implements</span> GlobalFilter <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@Override</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> Mono<span style="color:#f92672">&lt;</span>Void<span style="color:#f92672">&gt;</span> <span style="color:#a6e22e">filter</span><span style="color:#f92672">(</span>ServerWebExchange exchange<span style="color:#f92672">,</span> GatewayFilterChain chain<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        String token <span style="color:#f92672">=</span> exchange<span style="color:#f92672">.</span><span style="color:#a6e22e">getRequest</span><span style="color:#f92672">().</span><span style="color:#a6e22e">getQueryParams</span><span style="color:#f92672">().</span><span style="color:#a6e22e">getFirst</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;token&#34;</span><span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">if</span> <span style="color:#f92672">(</span>StringUtils<span style="color:#f92672">.</span><span style="color:#a6e22e">isBlank</span><span style="color:#f92672">(</span>token<span style="color:#f92672">))</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>            System<span style="color:#f92672">.</span><span style="color:#a6e22e">out</span><span style="color:#f92672">.</span><span style="color:#a6e22e">println</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;鉴权失败&#34;</span><span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>            exchange<span style="color:#f92672">.</span><span style="color:#a6e22e">getResponse</span><span style="color:#f92672">().</span><span style="color:#a6e22e">setStatusCode</span><span style="color:#f92672">(</span>HttpStatus<span style="color:#f92672">.</span><span style="color:#a6e22e">UNAUTHORIZED</span><span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>            <span style="color:#66d9ef">return</span> exchange<span style="color:#f92672">.</span><span style="color:#a6e22e">getResponse</span><span style="color:#f92672">().</span><span style="color:#a6e22e">setComplete</span><span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> chain<span style="color:#f92672">.</span><span style="color:#a6e22e">filter</span><span style="color:#f92672">(</span>exchange<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div></li>
<li>
<p>启动并测试</p>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111501855.png" alt="image-20201030172557201"></strong></p>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111501890.png" alt="image-20201030172635132"></strong></p>
</li>
</ol>
<h2 id="77-集成sentinel实现网关限流">7.7 集成Sentinel实现网关限流</h2>
<p>网关是所有请求的公共入口，所以可以在网关进行限流，而且限流的方式也很多，我们本次采用前面学过的Sentinel组件来实现网关的限流。Sentinel支持对SpringCloud Gateway、Zuul等主流网关进行限流。</p>
<p>从1.6.0版本开始，Sentinel提供了SpringCloud Gateway的适配模块，可以提供两种资源维度的限流：</p>
<ul>
<li>
<p>route维度：即在Spring配置文件中配置的路由条目，资源名为对应的routeId</p>
</li>
<li>
<p>自定义API维度：用户可以利用Sentinel提供的API来自定义一些API分组</p>
</li>
</ul>
<h3 id="771-网关集成sentinel">7.7.1 网关集成Sentinel</h3>
<p><a href="https://github.com/alibaba/Sentinel/wiki/">https://github.com/alibaba/Sentinel/wiki/</a>网关限流</p>
<ol>
<li>
<p>添加依赖</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-xml" data-lang="xml"><span style="display:flex;"><span><span style="color:#f92672">&lt;dependency&gt;</span>
</span></span><span style="display:flex;"><span>	<span style="color:#f92672">&lt;groupId&gt;</span>com.alibaba.csp<span style="color:#f92672">&lt;/groupId&gt;</span>
</span></span><span style="display:flex;"><span>	<span style="color:#f92672">&lt;artifactId&gt;</span>sentinel-spring-cloud-gateway-adapter<span style="color:#f92672">&lt;/artifactId&gt;</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">&lt;/dependency&gt;</span>
</span></span></code></pre></div></li>
<li>
<p>编写配置类</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span>    <span style="color:#f92672">package</span> cn.czh0123.config<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@Configuration</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">GatewayConfiguration</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">private</span> <span style="color:#66d9ef">final</span> List<span style="color:#f92672">&lt;</span>ViewResolver<span style="color:#f92672">&gt;</span> viewResolvers<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">private</span> <span style="color:#66d9ef">final</span> ServerCodecConfigurer serverCodecConfigurer<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">public</span> <span style="color:#a6e22e">GatewayConfiguration</span><span style="color:#f92672">(</span>ObjectProvider<span style="color:#f92672">&lt;</span>List<span style="color:#f92672">&lt;</span>ViewResolver<span style="color:#f92672">&gt;&gt;</span> viewResolversProvider<span style="color:#f92672">,</span>
</span></span><span style="display:flex;"><span>                                    ServerCodecConfigurer serverCodecConfigurer<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>            <span style="color:#66d9ef">this</span><span style="color:#f92672">.</span><span style="color:#a6e22e">viewResolvers</span> <span style="color:#f92672">=</span> viewResolversProvider<span style="color:#f92672">.</span><span style="color:#a6e22e">getIfAvailable</span><span style="color:#f92672">(</span>Collections<span style="color:#f92672">::</span>emptyList<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>            <span style="color:#66d9ef">this</span><span style="color:#f92672">.</span><span style="color:#a6e22e">serverCodecConfigurer</span> <span style="color:#f92672">=</span> serverCodecConfigurer<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>        <span style="color:#75715e">// 配置限流的异常处理器
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>        <span style="color:#a6e22e">@Bean</span>
</span></span><span style="display:flex;"><span>        <span style="color:#a6e22e">@Order</span><span style="color:#f92672">(</span>Ordered<span style="color:#f92672">.</span><span style="color:#a6e22e">HIGHEST_PRECEDENCE</span><span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">public</span> SentinelGatewayBlockExceptionHandler <span style="color:#a6e22e">sentinelGatewayBlockExceptionHandler</span><span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>            <span style="color:#75715e">// Register the block exception handler for Spring Cloud Gateway.
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>            <span style="color:#66d9ef">return</span> <span style="color:#66d9ef">new</span> SentinelGatewayBlockExceptionHandler<span style="color:#f92672">(</span>viewResolvers<span style="color:#f92672">,</span> serverCodecConfigurer<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>        <span style="color:#75715e">// 初始化一个限流的过滤器
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>        <span style="color:#a6e22e">@Bean</span>
</span></span><span style="display:flex;"><span>        <span style="color:#a6e22e">@Order</span><span style="color:#f92672">(</span>Ordered<span style="color:#f92672">.</span><span style="color:#a6e22e">HIGHEST_PRECEDENCE</span><span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">public</span> GlobalFilter <span style="color:#a6e22e">sentinelGatewayFilter</span><span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>            <span style="color:#66d9ef">return</span> <span style="color:#66d9ef">new</span> SentinelGatewayFilter<span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>        <span style="color:#75715e">//增加对商品微服务的 限流
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>         <span style="color:#a6e22e">@PostConstruct</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">private</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">initGatewayRules</span><span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>            Set<span style="color:#f92672">&lt;</span>GatewayFlowRule<span style="color:#f92672">&gt;</span> rules <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> HashSet<span style="color:#f92672">&lt;&gt;();</span>
</span></span><span style="display:flex;"><span>            rules<span style="color:#f92672">.</span><span style="color:#a6e22e">add</span><span style="color:#f92672">(</span><span style="color:#66d9ef">new</span> GatewayFlowRule<span style="color:#f92672">(</span><span style="color:#e6db74">&#34;product_route&#34;</span><span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span>                    <span style="color:#f92672">.</span><span style="color:#a6e22e">setCount</span><span style="color:#f92672">(</span>3<span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span>                    <span style="color:#f92672">.</span><span style="color:#a6e22e">setIntervalSec</span><span style="color:#f92672">(</span>1<span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>            GatewayRuleManager<span style="color:#f92672">.</span><span style="color:#a6e22e">loadRules</span><span style="color:#f92672">(</span>rules<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span></code></pre></div></li>
<li>
<p>重启网关服务并测试.</p>
</li>
</ol>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111501522.png" alt="image-20201030175846125"></strong></p>
<h3 id="772-修改限流默认返回格式">7.7.2 修改限流默认返回格式</h3>
<ol>
<li>
<p>在配置类GatewayConfiguration.java中添加如下配置</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#a6e22e">@PostConstruct</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">initBlockHandlers</span><span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>	BlockRequestHandler blockRequestHandler <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> BlockRequestHandler<span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">public</span> Mono<span style="color:#f92672">&lt;</span>ServerResponse<span style="color:#f92672">&gt;</span> <span style="color:#a6e22e">handleRequest</span><span style="color:#f92672">(</span>ServerWebExchange serverWebExchange<span style="color:#f92672">,</span> Throwable throwable<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>		Map map <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> HashMap<span style="color:#f92672">&lt;&gt;();</span>
</span></span><span style="display:flex;"><span>		map<span style="color:#f92672">.</span><span style="color:#a6e22e">put</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;code&#34;</span><span style="color:#f92672">,</span> 0<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>		map<span style="color:#f92672">.</span><span style="color:#a6e22e">put</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;message&#34;</span><span style="color:#f92672">,</span> <span style="color:#e6db74">&#34;接口被限流了&#34;</span><span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>			<span style="color:#66d9ef">return</span> ServerResponse<span style="color:#f92672">.</span><span style="color:#a6e22e">status</span><span style="color:#f92672">(</span>HttpStatus<span style="color:#f92672">.</span><span style="color:#a6e22e">OK</span><span style="color:#f92672">).</span>
</span></span><span style="display:flex;"><span>				contentType<span style="color:#f92672">(</span>MediaType<span style="color:#f92672">.</span><span style="color:#a6e22e">APPLICATION_JSON</span><span style="color:#f92672">).</span>
</span></span><span style="display:flex;"><span>				body<span style="color:#f92672">(</span>BodyInserters<span style="color:#f92672">.</span><span style="color:#a6e22e">fromValue</span><span style="color:#f92672">(</span>map<span style="color:#f92672">));</span>
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">};</span>
</span></span><span style="display:flex;"><span>	GatewayCallbackManager<span style="color:#f92672">.</span><span style="color:#a6e22e">setBlockHandler</span><span style="color:#f92672">(</span>blockRequestHandler<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div></li>
<li>
<p>重启并测试</p>
<p><strong><img src="https://czh-pic.oss-cn-guangzhou.aliyuncs.com/202302111501478.png" alt="image-20201030180400822"></strong></p>
</li>
</ol>
<h3 id="773-自定义api分组">7.7.3 自定义API分组</h3>
<p>自定义API分组是一种更细粒度的限流规则定义</p>
<ol>
<li>
<p>在shop-order-server项目中添加ApiController</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#f92672">package</span> cn.czh0123.controller<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">@RestController</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">@RequestMapping</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;/api&#34;</span><span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">ApiController</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@RequestMapping</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;/hello&#34;</span><span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> String <span style="color:#a6e22e">api1</span><span style="color:#f92672">(){</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> <span style="color:#e6db74">&#34;api&#34;</span><span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div></li>
<li>
<p>重启shop-order-server项目.</p>
</li>
<li>
<p>在api-gateway项目的配置GatewayConfiguration.java中添加如下配置:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#a6e22e">@PostConstruct</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">private</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">initCustomizedApis</span><span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>	Set<span style="color:#f92672">&lt;</span>ApiDefinition<span style="color:#f92672">&gt;</span> definitions <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> HashSet<span style="color:#f92672">&lt;&gt;();</span>
</span></span><span style="display:flex;"><span>	ApiDefinition api1 <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> ApiDefinition<span style="color:#f92672">(</span><span style="color:#e6db74">&#34;order_api&#34;</span><span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span>                <span style="color:#f92672">.</span><span style="color:#a6e22e">setPredicateItems</span><span style="color:#f92672">(</span><span style="color:#66d9ef">new</span> HashSet<span style="color:#f92672">&lt;</span>ApiPredicateItem<span style="color:#f92672">&gt;()</span> <span style="color:#f92672">{{</span>
</span></span><span style="display:flex;"><span>                    add<span style="color:#f92672">(</span><span style="color:#66d9ef">new</span> ApiPathPredicateItem<span style="color:#f92672">().</span><span style="color:#a6e22e">setPattern</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;/order-serv/api/**&#34;</span><span style="color:#f92672">).</span>                 setMatchStrategy<span style="color:#f92672">(</span>SentinelGatewayConstants<span style="color:#f92672">.</span><span style="color:#a6e22e">URL_MATCH_STRATEGY_PREFIX</span><span style="color:#f92672">));</span>
</span></span><span style="display:flex;"><span>                <span style="color:#f92672">}});</span>
</span></span><span style="display:flex;"><span>	definitions<span style="color:#f92672">.</span><span style="color:#a6e22e">add</span><span style="color:#f92672">(</span>api1<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>	GatewayApiDefinitionManager<span style="color:#f92672">.</span><span style="color:#a6e22e">loadApiDefinitions</span><span style="color:#f92672">(</span>definitions<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">@PostConstruct</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">private</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">initGatewayRules</span><span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>	Set<span style="color:#f92672">&lt;</span>GatewayFlowRule<span style="color:#f92672">&gt;</span> rules <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> HashSet<span style="color:#f92672">&lt;&gt;();</span>
</span></span><span style="display:flex;"><span>	rules<span style="color:#f92672">.</span><span style="color:#a6e22e">add</span><span style="color:#f92672">(</span><span style="color:#66d9ef">new</span> GatewayFlowRule<span style="color:#f92672">(</span><span style="color:#e6db74">&#34;product_route&#34;</span><span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span>                <span style="color:#f92672">.</span><span style="color:#a6e22e">setCount</span><span style="color:#f92672">(</span>3<span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span>                <span style="color:#f92672">.</span><span style="color:#a6e22e">setIntervalSec</span><span style="color:#f92672">(</span>1<span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span>	<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>	rules<span style="color:#f92672">.</span><span style="color:#a6e22e">add</span><span style="color:#f92672">(</span><span style="color:#66d9ef">new</span> GatewayFlowRule<span style="color:#f92672">(</span><span style="color:#e6db74">&#34;order_api&#34;</span><span style="color:#f92672">).</span>
</span></span><span style="display:flex;"><span>                setCount<span style="color:#f92672">(</span>1<span style="color:#f92672">).</span>
</span></span><span style="display:flex;"><span>                setIntervalSec<span style="color:#f92672">(</span>1<span style="color:#f92672">));</span>
</span></span><span style="display:flex;"><span>    GatewayRuleManager<span style="color:#f92672">.</span><span style="color:#a6e22e">loadRules</span><span style="color:#f92672">(</span>rules<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div></li>
<li>
<p>直接访问http://localhost:8091/api/hello 是不会发生限流的，访问http://localhost:9000/order-serv/api/hello 就会出现限流了.</p>
</li>
</ol>

    <h4><a href="https://czh-dev.gitee.io/czh-blog.gitee.io/">Back to Home</a></h4>
  </div>

  <div class="span3 bs-docs-sidebar" style="position:fixed;right: 40px;top: 50px;">
    <h1>catalogue</h1>
    <ul class="nav nav-list bs-docs-sidenav">
      <div class="toc-div">
        <nav id="TableOfContents">
  <ul>
    <li><a href="#71-常见网关介绍">7.1 常见网关介绍</a></li>
    <li><a href="#72-gateway简介">7.2 Gateway简介</a></li>
    <li><a href="#73-gateway快速入门">7.3 Gateway快速入门</a></li>
    <li><a href="#74-自定义路由规则">7.4 自定义路由规则</a></li>
    <li><a href="#75-gateway概念">7.5 Gateway概念</a></li>
    <li><a href="#76-过滤器filter">7.6 过滤器Filter</a>
      <ul>
        <li><a href="#761-局部路由过滤器">7.6.1 局部路由过滤器</a></li>
        <li><a href="#762-全局路由过滤器">7.6.2 全局路由过滤器</a></li>
      </ul>
    </li>
    <li><a href="#77-集成sentinel实现网关限流">7.7 集成Sentinel实现网关限流</a>
      <ul>
        <li><a href="#771-网关集成sentinel">7.7.1 网关集成Sentinel</a></li>
        <li><a href="#772-修改限流默认返回格式">7.7.2 修改限流默认返回格式</a></li>
        <li><a href="#773-自定义api分组">7.7.3 自定义API分组</a></li>
      </ul>
    </li>
  </ul>
</nav>
      </div>
    </ul>
  </div>

</div>
<script src="https://cdn.jsdelivr.net/npm/gumshoejs@5.1.2/dist/gumshoe.min.js"></script>
<script>
  var spy = new Gumshoe('#TableOfContents a', {
    nested: true,
    nestedClass: 'active'
  });
</script>
<style>
   
  #TableOfContents li,
  #TableOfContents ul {
    list-style-type: none;
  }

  #TableOfContents ul {
    padding-left: 0px;
  }

  #TableOfContents li>a {
    display: block;
    padding: 4px 20px;
    font-size: 95%;
    color: #000000;
  }

  #TableOfContents li>a:hover,
  #TableOfContents li>a:focus {
    padding-left: 19px;
    color: #3A6bA5;
    text-decoration: none;
    background-color: transparent;
    border-left: 1px solid #3A6bA5;
  }

  #TableOfContents li.active>a,
  #TableOfContents li.active>a:hover,
  #TableOfContents li.active>a:focus {
    padding-left: 18px;
    font-weight: bold;
    color: #3A6bA5;
    background-color: transparent;
    border-left: 2px solid #3A6bA5;
  }

   
  #TableOfContents li>ul {
    padding-bottom: 10px;
  }

  #TableOfContents li li>a {
    padding-top: 1px;
    padding-bottom: 1px;
    padding-left: 30px;
    font-size: 14px;
    font-weight: normal;
  }

  #TableOfContents li li>a:hover,
  #TableOfContents li li>a:focus {
    padding-left: 29px;
  }

  #TableOfContents li li.active>a,
  #TableOfContents li li.active>a:hover,
  #TableOfContents li li.active>a:focus {
    padding-left: 28px;
    font-weight: 500;
  }

  #TableOfContents .nav-link.active+ul {
    display: block;
  }

  #TableOfContents li>ul {
    display: none;
  }

  #TableOfContents li.active>ul {
    display: inherit;
  }

  .toc-div {
    position: -webkit-sticky;
     
    position: sticky;
     
    top: 20px;
  }
</style>


        </div><footer class="container">
    <hr class="soften">
    <p>
    <a href="https://space.bilibili.com/1799809923">Love eating fried pork ribs</a> | 

&copy; 
<a href="http://jmf-portfolio.netlify.com" target="_blank">
    JM Fergeau
</a>
<span id="thisyear">2023</span>

    | My site


        | Built on <a href="//gohugo.io" target="_blank">Hugo</a>

</p>
    <p class="text-center">
        <a href="https://facebook.com">Facebook</a> 
        <a href="https://twitter.com">Twitter</a> 
        <a href="https://linkedin.com">Linkedin</a> 
        <a href="https://github.com">GitHub</a> 
        <a href="https://gitlab.com">GitLab</a>
    </p>
</footer>

</body><link rel="stylesheet" href="/czh-blog.gitee.io/css/bootstrap.css">
<link rel="stylesheet" href="/czh-blog.gitee.io/css/bootstrap-responsive.css">
<link rel="stylesheet" href="/czh-blog.gitee.io/css/style.css">

<script src="/czh-blog.gitee.io/js/jquery.js"></script>
<script src="/czh-blog.gitee.io/js/bootstrap-386.js"></script>
<script src="/czh-blog.gitee.io/js/bootstrap-transition.js"></script>
<script src="/czh-blog.gitee.io/js/bootstrap-alert.js"></script>
<script src="/czh-blog.gitee.io/js/bootstrap-modal.js"></script>
<script src="/czh-blog.gitee.io/js/bootstrap-dropdown.js"></script>
<script src="/czh-blog.gitee.io/js/bootstrap-scrollspy.js"></script>
<script src="/czh-blog.gitee.io/js/bootstrap-tab.js"></script>
<script src="/czh-blog.gitee.io/js/bootstrap-tooltip.js"></script>
<script src="/czh-blog.gitee.io/js/bootstrap-popover.js"></script>
<script src="/czh-blog.gitee.io/js/bootstrap-button.js"></script>
<script src="/czh-blog.gitee.io/js/bootstrap-collapse.js"></script>
<script src="/czh-blog.gitee.io/js/bootstrap-carousel.js"></script>
<script src="/czh-blog.gitee.io/js/bootstrap-typeahead.js"></script>
<script src="/czh-blog.gitee.io/js/bootstrap-affix.js"></script>
<script>
    _386 = { 
        fastLoad: false ,
        onePass: false , 
        speedFactor: 1 
    };

    
    function ThisYear() {
        document.getElementById('thisyear').innerHTML = new Date().getFullYear();
    };
</script>
</html>
